/* Play MP3 Stream from Baidu Text to Speech service

   This example code is in the Public Domain (or CC0 licensed, at your option.)

   Unless required by applicable law or agreed to in writing, this
   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
   CONDITIONS OF ANY KIND, either express or implied.
*/
#include <sys/time.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"

#include "esp_log.h"
#include "esp_wifi.h"
#include "nvs_flash.h"
#include "sdkconfig.h"
#include "audio_element.h"
#include "audio_pipeline.h"
#include "audio_event_iface.h"
#include "audio_common.h"
#include "http_stream.h"
#include "i2s_stream.h"
#include "mp3_decoder.h"

#include "esp_peripherals.h"
#include "periph_wifi.h"
#include "board.h"
#include "esp_http_client.h"
#include "baidu_access_token.h"

#include "audio_idf_version.h"

//Luke Liu
#include "lvgl.h"
#include "lv_demo_music.h"
#include "lv_port.h"
#include "lv_gui.h"


// 按键组件
#include "periph_adc_button.h"
#include "input_key_service.h"

// ai chat
#include "baidu_access_token.h"
#include "baidu_tts.h"
#include "baidu_vtt.h"
#include "minimax_chat.h"


#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 1, 0))
#include "esp_netif.h"
#else
#include "tcpip_adapter.h"
#endif

static const char *TAG = "BAIDU_SPEECH_EXAMPLE";

#define BAIDU_TTS_ENDPOINT "http://tsn.baidu.com/text2audio"
#define TTS_TEXT "感谢你关注三哥，三哥正在招募开发合伙人，有意请联系我"

char *baidu_access_token;
static char request_data[1024];

static EventGroupHandle_t my_event_group;
#define ALL_REDAY   BIT0

extern lv_obj_t *label1;
extern lv_obj_t *label2;
//extern char ask_text[256];
extern char ask_text[256];  // 存储提问的文字 

extern char minimax_content[2048];
extern int ask_flag = 0;
int answer_flag = 0;
int lcd_clear_flag = 0;

// ai chat
char *baidu_access_token = NULL;
baidu_vtt_handle_t vtt;
baidu_tts_handle_t tts;
audio_event_iface_handle_t evt = NULL;

static esp_periph_config_t periph_cfg ;//= DEFAULT_ESP_PERIPH_SET_CONFIG();
static esp_periph_set_handle_t set = NULL;//esp_periph_set_init(&periph_cfg);

// 把下面的xxx替换成自己的token_key
const char * minimax_key = MINIMAX_KEY;//"Bearer eyJhbGxxx";


int _http_stream_event_handle(http_stream_event_msg_t *msg)
{
    esp_http_client_handle_t http_client = (esp_http_client_handle_t)msg->http_client;

    if (msg->event_id != HTTP_STREAM_PRE_REQUEST) {
        return ESP_OK;
    }

    if (baidu_access_token == NULL) {
        // Must freed `baidu_access_token` after used
        baidu_access_token = baidu_get_access_token(CONFIG_BAIDU_ACCESS_KEY, CONFIG_BAIDU_SECRET_KEY);
    }

    if (baidu_access_token == NULL) {
        ESP_LOGE(TAG, "Error issuing access token");
        return ESP_FAIL;
    }

    int data_len = snprintf(request_data, 1024, "lan=zh&cuid=ESP32&ctp=1&tok=%s&tex=%s", baidu_access_token, TTS_TEXT);
    esp_http_client_set_post_field(http_client, request_data, data_len);
    esp_http_client_set_method(http_client, HTTP_METHOD_POST);
    return ESP_OK;
}

static esp_err_t input_key_service_cb(periph_service_handle_t handle, periph_service_event_t *evt, void *ctx)
{
    ESP_LOGD(TAG, "[ * ] input key id is %d, %d", (int)evt->data, evt->type);
    const char *key_types[INPUT_KEY_SERVICE_ACTION_PRESS_RELEASE + 1] = {"UNKNOWN", "CLICKED", "CLICK RELEASED", "PRESSED", "PRESS RELEASED"};
    switch ((int)evt->data) {
        case INPUT_KEY_USER_ID_REC:
            ESP_LOGI(TAG, "[ * ] [Rec] KEY %s", key_types[evt->type]);
	
			if (evt->type == INPUT_KEY_SERVICE_ACTION_PRESS) {
				baidu_tts_stop(tts);
				ESP_LOGI(TAG, "[ * ] baidu_vtt_start Resuming pipeline");
				lcd_clear_flag = 1;
				baidu_vtt_start(vtt);
			} else if (evt->type == INPUT_KEY_SERVICE_ACTION_PRESS_RELEASE || evt->type == INPUT_KEY_SERVICE_ACTION_CLICK_RELEASE) 
			{
				ESP_LOGI(TAG, "[ * ] Stop pipeline");
			
				char *original_text = baidu_vtt_stop(vtt);
				if (original_text == NULL) {
					minimax_content[0]=0; // 清空minimax 第1个字符写0就可以
					//continue;
				}
				ESP_LOGI(TAG, "Original text = %s", original_text);
				ask_flag = 1;
			
				char *answer = minimax_chat(original_text);
				if (answer == NULL)
				{
					//continue;
				}else
				{
				ESP_LOGI(TAG, "minimax answer = %s", answer);
				answer_flag = 1;
				es8311_pa_power(true); // 打开音频
				baidu_tts_start(tts, answer);
				}
			}
            break;
        case INPUT_KEY_USER_ID_SET:
            ESP_LOGI(TAG, "[ * ] [SET] KEY %s", key_types[evt->type]);
            break;
        case INPUT_KEY_USER_ID_PLAY:
            ESP_LOGI(TAG, "[ * ] [Play] KEY %s", key_types[evt->type]);
            break;
        case INPUT_KEY_USER_ID_MODE:
            ESP_LOGI(TAG, "[ * ] [MODE] KEY %s", key_types[evt->type]);
            break;
        case INPUT_KEY_USER_ID_VOLDOWN:
            ESP_LOGI(TAG, "[ * ] [Vol-] KEY %s", key_types[evt->type]);
            break;
        case INPUT_KEY_USER_ID_VOLUP:
            ESP_LOGI(TAG, "[ * ] [Vol+] KEY %s", key_types[evt->type]);
            break;
        case INPUT_KEY_USER_ID_MUTE:
            ESP_LOGI(TAG, "[ * ] [MUTE] KEY %s", key_types[evt->type]);
            break;
        case INPUT_KEY_USER_ID_CAPTURE:
            ESP_LOGI(TAG, "[ * ] [CAPTURE] KEY %s", key_types[evt->type]);
            break;
        case INPUT_KEY_USER_ID_MSG:
            ESP_LOGI(TAG, "[ * ] [MSG] KEY %s", key_types[evt->type]);
            break;
        case INPUT_KEY_USER_ID_BATTERY_CHARGING:
            ESP_LOGI(TAG, "[ * ] [BATTERY_CHARGING] KEY %s", key_types[evt->type]);
            break;
        case INPUT_KEY_USER_ID_WAKEUP:
            ESP_LOGI(TAG, "[ * ] [WAKEUP] KEY %s", key_types[evt->type]);
            break;
        case INPUT_KEY_USER_ID_COLOR:
            ESP_LOGI(TAG, "[ * ] [COLOR] KEY %s", key_types[evt->type]);
            break;
        default:
            ESP_LOGE(TAG, "User Key ID[%d] does not support", (int)evt->data);
            break;
    }

    return ESP_OK;
}

void key_start(esp_periph_set_handle_t set)
{
	esp_periph_handle_t key_handle;
    ESP_LOGI(TAG, "[ key_start 00]");
    key_handle = audio_board_key_init(set);

    ESP_LOGI(TAG, "[ key_start 01] ");
    input_key_service_info_t input_key_info[] = INPUT_KEY_DEFAULT_INFO();
    input_key_service_cfg_t input_cfg = INPUT_KEY_SERVICE_DEFAULT_CONFIG();
    input_cfg.handle = set;
    input_cfg.based_cfg.task_stack = 3 * 1024;
    periph_service_handle_t input_ser = input_key_service_create(&input_cfg);

    input_key_service_add_key(input_ser, input_key_info, INPUT_KEY_NUM);
    //periph_service_set_callback(input_ser, input_key_service_cb, NULL);

    ESP_LOGW(TAG, "[ 4 ] Waiting for a button to be pressed ...");
}

esp_periph_handle_t audio_key_start(esp_periph_set_handle_t set)
{
    periph_adc_button_cfg_t adc_btn_cfg = PERIPH_ADC_BUTTON_DEFAULT_CONFIG();
    adc_arr_t adc_btn_tag = ADC_DEFAULT_ARR();
    adc_btn_tag.total_steps = 6;
    adc_btn_tag.adc_ch = ADC1_CHANNEL_4;
    int btn_array[7] = {190, 600, 1000, 1375, 1775, 2195, 3000};
    adc_btn_tag.adc_level_step = btn_array;
    adc_btn_cfg.arr = &adc_btn_tag;
    adc_btn_cfg.arr_size = 1;
    if (audio_mem_spiram_stack_is_enabled()) {
        adc_btn_cfg.task_cfg.ext_stack = true;
    }
    esp_periph_handle_t adc_btn_handle = periph_adc_button_init(&adc_btn_cfg);
    AUDIO_NULL_CHECK(TAG, adc_btn_handle, return ESP_ERR_ADF_MEMORY_LACK);
    return adc_btn_handle;//esp_periph_start(set, adc_btn_handle);
}

/**************************** LVGL主界面更新函数 **********************************/


void value_update_cb(lv_timer_t * timer)
{
    if (ask_flag == 1)
    {
        lv_label_set_text_fmt(label1, "我：%s", ask_text);
        ask_flag = 0;
    }
    if (answer_flag == 1)
    {
        lv_label_set_text_fmt(label2, "AI：%s", minimax_content);
        answer_flag = 0;
    }
    if(lcd_clear_flag == 1)
    {
        lcd_clear_flag = 0;
        lv_label_set_text(label1, "我：");
        lv_label_set_text(label2, "AI：");
    }
}
void ai_chat_task(void *pv)
{
	
	ESP_LOGI(TAG,"ai_chat_task");
	
    ESP_LOGI(TAG, "[ 0 ] Start and wait for Wi-Fi network");
	
    periph_wifi_cfg_t wifi_cfg = {
        .wifi_config.sta.ssid = CONFIG_WIFI_SSID,
        .wifi_config.sta.password = CONFIG_WIFI_PASSWORD,
    };
    esp_periph_handle_t wifi_handle = periph_wifi_init(&wifi_cfg);

    // Initialize Button peripheral
	//esp_periph_handle_t button_handle = audio_key_start(set);
	key_start(set);

	ESP_LOGI(TAG,"audio_key_start done");


    // Start wifi & button peripheral
    //esp_periph_start(set, button_handle);
    esp_periph_start(set, wifi_handle);

    periph_wifi_wait_for_connected(wifi_handle, portMAX_DELAY);

    // 百度token计算
    if (baidu_access_token == NULL) {
        // Must freed `baidu_access_token` after used
        baidu_access_token = baidu_get_access_token(CONFIG_BAIDU_ACCESS_KEY, CONFIG_BAIDU_SECRET_KEY);
    }

	audio_board_handle_t board_handle = audio_board_init();
	audio_hal_ctrl_codec(board_handle->audio_hal, AUDIO_HAL_CODEC_MODE_BOTH, AUDIO_HAL_CTRL_START);
	
	// 百度 语音转文字 初始化
	baidu_vtt_config_t vtt_config = {
		.record_sample_rates = 16000,
		.encoding = ENCODING_LINEAR16,
	};
	baidu_vtt_handle_t vtt = baidu_vtt_init(&vtt_config);

	// 百度 文字转语音 初始化
	baidu_tts_config_t tts_config = {
		.playback_sample_rate = 16000,
	};
	baidu_tts_handle_t tts = baidu_tts_init(&tts_config);

	// 监听“流”
	ESP_LOGI(TAG, "[ 4 ] Set up  event listener");
	audio_event_iface_cfg_t evt_cfg = AUDIO_EVENT_IFACE_DEFAULT_CFG();
	audio_event_iface_handle_t evt = audio_event_iface_init(&evt_cfg);

	ESP_LOGI(TAG, "[4.1] Listening event from the pipeline");
	baidu_vtt_set_listener(vtt, evt);
	baidu_tts_set_listener(tts, evt);

	ESP_LOGI(TAG, "[4.2] Listening event from peripherals");
	audio_event_iface_set_listener(esp_periph_set_get_event_iface(set), evt);

	ESP_LOGI(TAG, "[ 5 ] Listen for all pipeline events");

	//es8311_pa_power(true); // 打开音频
	//baidu_tts_start(tts, TTS_TEXT);

	// 给出 “已经准备好” 信号
	xEventGroupSetBits(my_event_group, ALL_REDAY);

	while (1) {
		
		audio_event_iface_msg_t msg;
		if (audio_event_iface_listen(evt, &msg, portMAX_DELAY) != ESP_OK) {
			ESP_LOGW(TAG, "[ * ] Event process failed: src_type:%d, source:%p cmd:%d, data:%p, data_len:%d",
					 msg.source_type, msg.source, msg.cmd, msg.data, msg.data_len);
			continue;
		}
		
		ESP_LOGI(TAG, "[ * ] Event received: src_type:%d, source:%p cmd:%d, data:%p, data_len:%d",
				 msg.source_type, msg.source, msg.cmd, msg.data, msg.data_len);
		
		if (baidu_tts_check_event_finish(tts, &msg)) {
			ESP_LOGI(TAG, "[ * ] TTS Finish");
			//es8311_pa_power(false); // 关闭音频
			continue;
		}
		
		if ((int)msg.data == get_input_mode_id()) {
			break;
		}
		
		if ((int)msg.data != get_input_rec_id()) {
			continue;
		}
		ESP_LOGI(TAG,"msg.cmd=%d",msg.cmd);
		if (msg.cmd == PERIPH_ADC_BUTTON_PRESSED) {
			baidu_tts_stop(tts);
			ESP_LOGI(TAG, "[ * ] Resuming pipeline");
			lcd_clear_flag = 1;
			baidu_vtt_start(vtt);
		} else if (msg.cmd == PERIPH_ADC_BUTTON_RELEASE || msg.cmd == PERIPH_ADC_BUTTON_LONG_RELEASE) 
		{
			ESP_LOGI(TAG, "[ * ] Stop pipeline");
			baidu_tts_stop(tts);
			char *original_text = baidu_vtt_stop(vtt);
			if (original_text == NULL) {
				minimax_content[0]=0; // 清空minimax 第1个字符写0就可以
				continue;
			}
			ESP_LOGI(TAG, "Original text = %s", original_text);
			ask_flag = 1;
		
			char *answer = minimax_chat(original_text);
			if (answer == NULL)
			{
				continue;
			}
			ESP_LOGI(TAG, "minimax answer = %s", answer);
			answer_flag = 1;
			//es8311_pa_power(true); // 打开音频
			baidu_tts_start(tts, answer);
		}
		// raise the task priority of LVGL and/or reduce the handler period can improve the performance
        //vTaskDelay(pdMS_TO_TICKS(10));
        // The task running lv_timer_handler should have lower priority than that running `lv_tick_inc`
        //lv_timer_handler();

	}
	
	ESP_LOGI(TAG, "[ 6 ] Stop audio_pipeline");
	baidu_vtt_destroy(vtt);
	baidu_tts_destroy(tts);
	// Stop all periph before removing the listener //
	esp_periph_set_stop_all(set);
	audio_event_iface_remove_listener(esp_periph_set_get_event_iface(set), evt);

	// Make sure audio_pipeline_remove_listener & audio_event_iface_remove_listener are called before destroying event_iface //
	audio_event_iface_destroy(evt);
	esp_periph_set_destroy(set);
	vTaskDelete(NULL);
	

}


static void main_page_task(void *pvParameters)
{
	ESP_LOGI(TAG,"main_page_task");
    xEventGroupWaitBits(my_event_group, ALL_REDAY, pdFALSE, pdFALSE, portMAX_DELAY);
    lv_obj_clean(lv_scr_act());
	ESP_LOGI(TAG,"lv_main_page");
    lv_main_page();
	ESP_LOGI(TAG,"lv_main_page done");
    lv_timer_create(value_update_cb, 200, NULL);  // 创建一个lv_timer

    while (1)
    {
        vTaskDelay(pdMS_TO_TICKS(1000));    
    }

    vTaskDelete(NULL);
}



void app_main(void)
{
    esp_log_level_set("*", ESP_LOG_INFO);
    esp_log_level_set(TAG, ESP_LOG_DEBUG);
    esp_log_level_set("HTTP_STREAM", ESP_LOG_DEBUG);
	// 按键组件

	ESP_LOGI(TAG,"nvs_flash_init start");
	esp_err_t err = nvs_flash_init();
    if (err == ESP_ERR_NVS_NO_FREE_PAGES) {
        // NVS partition was truncated and needs to be erased
        // Retry nvs_flash_init
        ESP_ERROR_CHECK(nvs_flash_erase());
        err = nvs_flash_init();
    }
#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 1, 0))
    ESP_ERROR_CHECK(esp_netif_init());
#else
    tcpip_adapter_init();
#endif

    ESP_LOGI(TAG, "[ 0 ] Start and wait for Wi-Fi network");
	periph_cfg.task_stack         = DEFAULT_ESP_PERIPH_STACK_SIZE;
    periph_cfg.task_prio          = DEFAULT_ESP_PERIPH_TASK_PRIO;
    periph_cfg.task_core          = DEFAULT_ESP_PERIPH_TASK_CORE;
    periph_cfg.extern_stack       = false;
	
    set = esp_periph_set_init(&periph_cfg);
    //Luke Liu
    esp_lcd_panel_handle_t panel_handle = audio_board_lcd_init(set, lcd_trans_done_cb);
    ESP_ERROR_CHECK(lv_port_init(panel_handle));
	ESP_LOGI(TAG,"lv_port_init done");
    //lv_demo_music();
    my_event_group = xEventGroupCreate();
    lv_gui_start();
	ESP_LOGI(TAG,"lv_demo_music done");

	ESP_LOGI(TAG,"main_page_task");
	xTaskCreate(main_page_task, "main_page_task", 8192, NULL, 5, NULL); 
	
	ESP_LOGI(TAG,"ai_chat_task");
	xTaskCreate(ai_chat_task, "ai_chat_task", 8192, NULL, 5, NULL);

	ESP_LOGI(TAG,"ai_chat_task finish");


    while(1) 
	{
				
		vTaskDelay(pdMS_TO_TICKS(10));
		//ESP_LOGI(TAG, "T");
        lv_task_handler();// Luke Liu merged music_player
	}
	
	ESP_LOGI(TAG, "[ 6 ] Stop audio_pipeline");
	
}
